feat(logging): add CerrLogger std::cerr backend (3/6)#724
Conversation
7f46cc5 to
0dbc548
Compare
d3237ab to
77acb0e
Compare
| std::string FormatLine(const LogMessage& message) { | ||
| auto now = | ||
| std::chrono::floor<std::chrono::milliseconds>(std::chrono::system_clock::now()); | ||
| return std::format("{:%Y-%m-%dT%H:%M:%S}Z {} [{}] {}:{}] {}\n", now, |
There was a problem hiding this comment.
The format has file:line], with a closing ] but no opening [. This looks like a typo. Please use [file:line] or file:line, and add a test that checks this part of the layout.
There was a problem hiding this comment.
Seems not resolved. See my comment below.
There was a problem hiding this comment.
Done. uploaded a wrong version.
77acb0e to
5a1845f
Compare
9989da5 to
865a07b
Compare
865a07b to
77f50dd
Compare
| std::string FormatLine(const LogMessage& message) { | ||
| auto now = | ||
| std::chrono::floor<std::chrono::milliseconds>(std::chrono::system_clock::now()); | ||
| return std::format("{:%Y-%m-%dT%H:%M:%S}Z {} [{}] {}:{}] {}\n", now, |
There was a problem hiding this comment.
The PR description says the layout is [file:line], but this still emits file:line]. Please update the format string, the header doc, and the regex test to use the same layout.
| util/struct_like_set.cc | ||
| util/task_group.cc | ||
| util/temporal_util.cc | ||
| util/thread_util_internal.cc |
There was a problem hiding this comment.
We can just use thread_util.cc as its name without internal suffix.
| std::string FormatLine(const LogMessage& message) { | ||
| auto now = | ||
| std::chrono::floor<std::chrono::milliseconds>(std::chrono::system_clock::now()); | ||
| return std::format("{:%Y-%m-%dT%H:%M:%S}Z {} [{}] {}:{}] {}\n", now, |
There was a problem hiding this comment.
Seems not resolved. See my comment below.
|
|
||
| /// \brief Trailing path component of a source file path. | ||
| std::string_view Basename(std::string_view path) noexcept { | ||
| auto pos = path.find_last_of("/\\"); |
There was a problem hiding this comment.
Is this platform compatible? Should we use std::filesystem?
96caa72 to
65d2d43
Compare
Third block: the first concrete sink, and the process default until the spdlog backend lands. - CerrLogger writes to std::cerr with a fixed line layout `YYYY-MM-DDThh:mm:ss.mmmZ LEVEL [tid] file:line] message`. Timestamps use UTC std::chrono floored to milliseconds (no gmtime/localtime -- thread-unsafe); the thread id is the OS-native id, cached per thread. - Level is a std::atomic<LogLevel>; a mutex guards the whole formatted-line write so concurrent lines never interleave. Log()/Flush() wrap stream ops in try/catch so the noexcept contract holds even if the stream throws. - MakeDefaultLogger() now returns CerrLogger. Wired into both builds and installed; cerr_logger_test covers layout, level filtering, and concurrent-write safety. Co-authored-by: Isaac
65d2d43 to
0b106c2
Compare
Part 4 of the logging stack (builds on #724). Adds the application-facing macros — the part most callers actually use. **What's here** - `ICEBERG_LOG_{TRACE,DEBUG,INFO,WARN,ERROR,CRITICAL,FATAL}`, the generic `ICEBERG_LOG(level, …)`, `ICEBERG_LOG_TO(logger, …)`, and `ICEBERG_LOG_RUNTIME_FMT` for runtime format strings. - `ICEBERG_LOG_ACTIVE_LEVEL` is a compile-time floor: statements below it are removed entirely. `ICEBERG_LOG_FATAL` always emits, flushes, then aborts. - Filtering is decided only by `ShouldLog()`; formatting happens only on the taken path and never throws (a bad format falls back safely). - Generic/runtime-format macros use the same lock-free fast path as the fixed-severity ones (the slot lock is taken only on the fatal/abort path). - Bare `LOG_*` aliases are opt-in via `ICEBERG_LOG_SHORT_MACROS`. **Build note** — sets `/Zc:preprocessor` on MSVC, required for the `__VA_OPT__` used by the macros. **Examples** — every macro takes a `std::format` string + args. The rendered line depends on the active backend; with the default `CerrLogger` it looks like: ``` ICEBERG_LOG_TRACE("entering scan for {}", table); 2026-06-16T10:59:41.186Z trace [12345] table_scan.cc:88] entering scan for db.t ICEBERG_LOG_DEBUG("cache miss key={}", key); 2026-06-16T10:59:41.186Z debug [12345] cache.cc:42] cache miss key=manifest-7 ICEBERG_LOG_INFO("loaded {} manifests in {} ms", n, ms); 2026-06-16T10:59:41.186Z info [12345] table_scan.cc:91] loaded 5 manifests in 12 ms ICEBERG_LOG_WARN("retry {} after {}", attempt, err); 2026-06-16T10:59:41.186Z warn [12345] io.cc:51] retry 2 after timeout ICEBERG_LOG_ERROR("commit failed: {}", status); 2026-06-16T10:59:41.186Z error [12345] txn.cc:77] commit failed: conflict ICEBERG_LOG_CRITICAL("metadata unreadable at {}", path); 2026-06-16T10:59:41.186Z critical [12345] meta.cc:30] metadata unreadable at s3://b/m.json ICEBERG_LOG_FATAL("unrecoverable: {}", reason); // emits, flushes, then std::abort() 2026-06-16T10:59:41.186Z fatal [12345] boot.cc:19] unrecoverable: bad config ``` Less common forms: `ICEBERG_LOG(level, …)` (runtime severity), `ICEBERG_LOG_TO(logger, level, …)` (explicit logger), `ICEBERG_LOG_RUNTIME_FMT(level, fmt_string, args…)` (non-literal format). The same examples are documented inline in `logger.h`. **Tests** — `macros_test` / `macros_active_level_test`: formatting, level gating, "argument not evaluated when disabled", compile-time stripping, never-throws, and FATAL-aborts death tests. clang/libc++. This pull request and its description were written by Isaac.
Part 3 of the logging stack — now based on
main(#723 merged). Adds the first concrete sink: a dependency-freestd::cerrlogger, also the default backend when spdlog is off.What's here
CerrLoggerwrites one line per record:YYYY-MM-DDThh:mm:ss.mmmZ LEVEL [tid] [file:line] message.util/thread_util.h), lock-free level check, and a whole-line mutex so concurrent records never interleave.Log/Flushnever throw. Inherits the baseInitialize("level");patternis ignored (fixed layout; only the spdlog backend honorspattern).Tests (
cerr_logger_test): level filtering, the fixed line layout incl. the.mmmfield and[file:line], inheritedInitialize,Flush, never-throw when the sink itself throws, and concurrent-write non-interleaving. Built/run under clang-libc++; ASan + TSan clean.This pull request and its description were written by Isaac.